package com.qdd.freight.handler.impl;

import com.qdd.freight.anno.Mode;
import com.qdd.freight.entity.Datas;
import com.qdd.freight.handler.AbstractDeliveryHandler;
import com.qdd.freight.pojo.Delivery;
import com.qdd.freight.pojo.GoodsShip;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Map;

/**
 * 普通快递运价计算处理器
 *
 * @ClassName DBHandler
 * @Description TODO
 * @Author yanpeihao
 * @Date 2019/12/6 22:50
 * @Version 1.1
 **/

@Component
@Mode("1")
public class NorlDelHandler extends AbstractDeliveryHandler {

    //快运方式名称
    private static final String YFMODE_NAME = "普通快递";
    //对应数据库的字段名
    private static final String TABLE_FIELD_NAME = "ship_id";
    //对应数据库的字段映射值
    private static final String CONSTANT_FIELD_NAME = "shipId";


    @Override
    public String getShipFieldNameFromInstance() {
        return CONSTANT_FIELD_NAME;
    }


    /**
     * 具体运价计算实现逻辑
     *
     * @return
     * @Param boxVolume  箱体积
     * @Param shipId  运输方式id
     * @Param modeId 快递
     * @Param goodsId 商品id
     * @Param entId 仓库id
     * @Param singleVolume 单件体积
     * @Param quantity 采购数量
     * @Param boxWeight 箱重
     * @Param singleWeight 单重
     * @Param QTYRate 箱规
     */
    @Override
    public Datas realHandle(GoodsShip goodsShip, Integer shipId, Integer modeId, Integer goodsId, Integer entId,
                            Integer quantity, Integer company, String consignee, Double boxVolume, Double singleVolume,
                            Double boxWeight, Double singleWeight, Integer QTYRate) throws Exception {
        //获取对象
        Delivery delivery = getDelivery(shipId);
        //获取可用的计价参数
        //1.2调用父类方法获取可用的计价方式参数
        Map<String, Object> params = getAvailableParams(delivery, shipId, consignee);
        //获取默认价格
        Integer startingWeight = (Integer) params.get("startingWeight");
        Double startingPrice = (Double) params.get("startingPrice");
        Integer headWeight = (Integer) params.get("headWeight");
        Double headPrice = (Double) params.get("headPrice");
        Integer extensionWeight = (Integer) params.get("extensionWeight");
        Double extensionPrice = (Double) params.get("extensionPrice");
        //定义价格变量
        Double price = 0.00;
        //判断计价方式
        switch (delivery.getType()) {
            //按重量计算判断
            case 0:
                //获取运价信息
                price = weighInWeight(QTYRate, quantity, singleWeight, headWeight, headPrice, extensionWeight, extensionPrice);
                break;
            //按件数计算判断
            case 1:
                //获取运价信息
                price = byThePiece(quantity, startingWeight, startingPrice, headWeight, headPrice, extensionWeight, extensionPrice);
                break;
        }
        return packageDatas(modeId, goodsId, entId, quantity, price);
    }


    /**
     * 计重方式
     * 总价格=（首重价格+（（整箱总重量-首重重量）/续重规格）*续重单价）*（采购数量/箱规）
     * 备注：
     * 总重量1 = 箱规*单件重量
     * 整箱总重量 = 使用1和2之间的最大值。
     * 提示：
     * 首规格、续规格只可能时箱规的整数倍！！！！！！
     *
     * @return
     * @Param delivery  快递对象
     * @Param boxGauge  箱规
     * @Param singleWeight 单件重量
     * @Param unitVolume 单件体积
     * @Param GRWR 体积重量转换比
     * @Param extensionSpecs 续重规格 (起步重量-首重重量)/续重重量
     * @Param quantity 采购数量
     */
    private Double weighInWeight(Integer QTYRate, Integer quantity, Double singleWeight, Integer headWeight,
                                 Double headPrice, Integer extensionWeight, Double extensionPrice) {
        Double sumPrice = 0.00;
        BigDecimal bQuantity = BigDecimal.valueOf(quantity);
        BigDecimal bHeadPrice = BigDecimal.valueOf(headPrice);
        BigDecimal bHeadWeight = BigDecimal.valueOf(headWeight);
        BigDecimal bExtensionWeight = BigDecimal.valueOf(extensionWeight);
        BigDecimal bExtensionPrice = BigDecimal.valueOf(extensionPrice);
        BigDecimal bQTYRate = BigDecimal.valueOf(QTYRate);
        BigDecimal bSingleWeight = BigDecimal.valueOf(singleWeight);
        // 判断采购数量是否大于箱规
        if (quantity >= QTYRate) {
            if (singleWeight >= headWeight) {
                //计算运价逻辑
                //计算箱价
                BigDecimal sumBoxPrice = bHeadPrice.add(((bQTYRate.multiply(bSingleWeight).subtract(bHeadWeight)).divide(bExtensionWeight, 2).multiply(bExtensionPrice)))
                        .multiply(bQuantity.divide(bQTYRate, 0, BigDecimal.ROUND_FLOOR));
                //计算单件价
                BigDecimal sumSinglePrice = bHeadPrice.add(((bSingleWeight.subtract(bHeadWeight))
                        .divide(bExtensionWeight, 2).multiply(bExtensionPrice)))
                        .multiply(bQuantity.divideAndRemainder(bQTYRate)[1]);
                //总重量
                sumPrice = sumBoxPrice.add(sumSinglePrice).doubleValue();
            } else {
                // 若小于 首重价*数量
                sumPrice = bHeadPrice.multiply(bQuantity).doubleValue();
            }
        } else {
            // 判断单件重量是否大于首重，若大于采用
            // 总价格=（首重价格+（（整箱总重量-首重重量）/续重规格）*续重单价）*（采购数量/箱规）
            if (singleWeight >= headWeight) {
                sumPrice = bHeadPrice.add(((bSingleWeight.subtract(bHeadWeight))
                        .divide(bExtensionWeight, 2).multiply(bExtensionPrice)))
                        .multiply(bQuantity.divideAndRemainder(bQTYRate)[1]).doubleValue();
            } else {
                // 若小于 首重价*数量
                sumPrice = bHeadPrice.multiply(bQuantity).doubleValue();
            }
        }
        return sumPrice;
    }

    /**
     * 计件方式
     * 小于起步件数：
     * Double boxVolume , Double singleVolume等于起步价格
     * 大于起步件数：
     * 总价格=首件价格+（采购数量-首件件数）/续重规格）*续重单价
     * （采购数量-首件件数）/续重规格 = 续重的数量
     *
     * @return
     * @Param delivery 快递对象
     * @Param quantity 采购数量
     */
    private Double byThePiece(Integer quantity, Integer startingWeight, Double startingPrice, Integer headWeight,
                              Double headPrice, Integer extensionWeight, Double extensionPrice) {
        //小于起步件数
        if (quantity < startingWeight) {
            return startingPrice;
            //大于起步件数
        } else {
            return startingPriceCalculation(quantity, headWeight, headPrice, extensionWeight, extensionPrice);
        }
    }
}